FEXP Solver  1.0.0.0
FEXPConcurency.h
Go to the documentation of this file.
1 // © FEXP, FEXPEnterprise Solver, Ing. Vaclav Rek
3 // Provides base functionality for concurrency and parallelism.
4 // Compiler must support C++ ver.14 and later
6 #ifndef _CFEXPCONCURENCY_H_
7 #define _CFEXPCONCURENCY_H_
8 #include "FEXPCommon.h"
9 
10 // definition of constant for time measure
11 #define NANO_SEC 1.0E-9
12 // thread barrier used within the FEXP server
13 #define SERVER_THREAD_BARRIER CFEXPThreadGeneralBarrier
14 
16 // --> Windows specifics
18 // macro for checking windows version for supporting speciffic functionality
19 // specific to development in MS Visual Studio (2015)
20 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa383745.aspx
21 // https://msdn.microsoft.com/en-us/library/6sehtctf.aspx
22 // https://msdn.microsoft.com/cs-cz/library/windows/desktop/aa383745(v=vs.85).aspx
23 // it checks if windows version supports barriers
24 #define FEXPCOMMON_IS_WIN_BARR_SUPPORTED (NTDDI_VERSION <= FEXPCOMMON_MY_WIN_VERSION_FOR_COMPILATION)
25 
32 {
33 public:
34  using t_Procedure = std::function<void(void)>;
35  static bool RunProcedureTask(t_Procedure procedure, bool progressbar);
36  static bool RunProcedureTask(t_Procedure procedure, bool progressbar, std::string proc_desc, bool check_time_elapsed);
37 protected:
38  // [no protected members] -----------------------------
39 private:
40  // [no private members ] -----------------------------
41 };
42 
48 
51 {
52 public:
53  virtual ~ICFEXPConcurrencyBase() { }
54 
55  // pure virtual member functions
56  virtual void Dispose() = 0;
57 protected:
58  // [no protected members] -----------------------------
59 private:
60  // [no private members ] -----------------------------
61 };
62 
68 
71  : public ICFEXPConcurrencyBase
72 {
73 public:
74  ICFEXPSynchrThreadBarrier(size_t thrd_count) : _initial_thrd_count(thrd_count) { }
76 
77  // barrier instance creator
78  template<typename TBarrier>
79  static typename std::enable_if<std::is_base_of<ICFEXPSynchrThreadBarrier, TBarrier>::value, Ptr<TBarrier>>::type
80  GetInstance(std::size_t thread_count);
81 
82  // virtual member functions
83  virtual void SynchronizeThreads() = 0;
84  virtual size_t GetNumberOfThreads() { return _initial_thrd_count; }
85 protected:
86  const size_t _initial_thrd_count;
87 private:
88  // [no private members ] -----------------------------
89 };
90 
91 // member functions
93 //--------------------------------------------------------------------------------------
94 template<typename TBarrier>
95 typename std::enable_if<std::is_base_of<ICFEXPSynchrThreadBarrier, TBarrier>::value, Ptr<TBarrier>>::type
96 ICFEXPSynchrThreadBarrier::GetInstance(std::size_t thread_count)
97 //--------------------------------------------------------------------------------------
98 {
99  return (thread_count != 0) ?
101  : Ptr<TBarrier>(nullptr);
102 }
103 
111 
115 {
116 public:
117  explicit CFEXPThreadGeneralBarrier(std::size_t thread_count);
119 
120  // override of virtual member functions
121  virtual void SynchronizeThreads() override;
122  // override of virtual member functions
123  virtual void Dispose () override { }
124 protected:
125  // [no protected members] -----------------------------
126 private:
127  enum BarrierState : unsigned char { e_INCR, e_DECR };
128  std::mutex _mtx;
129  std::condition_variable _cond_var;
130  // info about the state of barrier
131  size_t _thrd_counter;
132  BarrierState _barrier_state;
133 };
134 
140 
144 {
145 public:
146  explicit CFEXPThreadWin8PLBarrier(std::size_t thread_count);
148 
149  // override of virtual member functions
150  virtual void SynchronizeThreads() override;
151  virtual void Dispose () override;
152 protected:
153  // [no protected members] -----------------------------
154 private:
155  // state of barrier information
156  bool _is_disposed;
157  LONG _thrd_counter;
158 #if FEXPCOMMON_IS_WIN_BARR_SUPPORTED
159  SYNCHRONIZATION_BARRIER _barrier;
160 #endif
161 };
162 
168 
171  : public ICFEXPConcurrencyBase
172 {
173 public:
174  virtual ~ICFEXPThreadBase() { }
175 
176  // pure virtual member functions
177  virtual void StartThread() = 0;
178  virtual void Join () = 0;
179  virtual void Detach () = 0;
180  virtual void Cancel () = 0;
181  virtual bool Canceling () = 0;
182 
183  // template functions for handling with input data
184  template<typename... VarArgs>
185  std::tuple<VarArgs...> GetInputDataTuple(VarArgs&&... args) { return std::tuple<VarArgs...>(args...); }
186  // empty function for data setting -- to override in child
187  template<typename TFunc, typename... VarArgs>
188  void SetInputData(std::function<TFunc> func, std::tuple<VarArgs...> args) { }
189 protected:
190  // [no protected members] -----------------------------
191 private:
192  // [no private members ] -----------------------------
193 };
194 
200 //https://stackoverflow.com/questions/13893060/i-want-to-kill-a-stdthread-using-its-thread-object
202  : public virtual std::exception
203 {
204 public:
205  virtual char const* what() const override { return "Thread interrupted!!!"; }
206 protected:
207  // [no protected members] -----------------------------
208 private:
209  // [no private members ] -----------------------------
210 };
211 
214 template<typename TThread>
215 void ThrowIfCancelRequest() noexcept(false)
216 {
217  auto test1 = TThread::_flag_ptr;
218  if (!test1)
219  return;
220  auto test2 = TThread::_flag_ptr->load();
221  if (!test2)
222  return;
223  // throw cancel exception
225 }
226 
232 
234 template<typename TFunc, typename... VarArgs>
236  : public ICFEXPThreadBase
237 {
238 public:
240  CFEXPCppThread(std::function<TFunc> func, VarArgs & ...args);
241  virtual ~CFEXPCppThread() { _flag_ptr = nullptr; }
242  // override pure virtual member fucntion
243  virtual void StartThread() override;
244  virtual void Join () override;
245  virtual void Detach () override;
246  virtual void Cancel () override;
247  virtual bool Canceling () override;
248  // override pure virtual member function to dispose object -- empty
249  virtual void Dispose () override { }
250 
251  // override base class template function -- little trick :-)
252  void SetInputData(std::function<TFunc> func, std::tuple<VarArgs...> args);
253 protected:
254  friend void ThrowIfCancelRequest<CFEXPCppThread<TFunc, VarArgs...>>();
255 private:
256  std::function<TFunc> _thread_func;
257  std::tuple<VarArgs...> _thread_args;
258  Ptr<std::thread> _thread;
259  //
260  static thread_local std::atomic_bool * _flag_ptr;
261  std::atomic_bool _flag;
262  // lazy thread creation with variable input parameters
263  template<std::size_t... Idx>
264  Ptr<std::thread> create_thread(const std::tuple<VarArgs...> & tuple, std::index_sequence<Idx...>);
265  template<std::size_t... Idx>
266  void runner(std::function<TFunc> func, const std::tuple<VarArgs...> & tuple, std::index_sequence<Idx...>);
267 };
268 
269 // member functions
271 //--------------------------------------------------------------------------------------
272 template<typename TFunc, typename... VarArgs>
273 thread_local std::atomic_bool * CFEXPCppThread<TFunc, VarArgs...>::_flag_ptr = nullptr;
274 //--------------------------------------------------------------------------------------
275 
276 //--------------------------------------------------------------------------------------
277 template<typename TFunc, typename... VarArgs>
278 CFEXPCppThread<TFunc, VarArgs...>::CFEXPCppThread(std::function<TFunc> func, VarArgs & ...args)
279  : ICFEXPThreadBase(), _flag(false)
280 //--------------------------------------------------------------------------------------
281 {
282  SetInputData(func, GetInputDataTuple(args...));
283 }
284 
285 //--------------------------------------------------------------------------------------
286 template<typename TFunc, typename... VarArgs>
287 void CFEXPCppThread<TFunc, VarArgs...>::SetInputData(std::function<TFunc> func, std::tuple<VarArgs...> args)
288 //--------------------------------------------------------------------------------------
289 {
290  _thread_func = func;
291  _thread_args = args;
292 }
293 
296 //--------------------------------------------------------------------------------------
297 template<typename TFunc, typename... VarArgs>
299 //--------------------------------------------------------------------------------------
300 {
301  if (_thread)
302  return;
303  _thread = create_thread(_thread_args, std::index_sequence_for<VarArgs...>());
304 }
305 
306 //--------------------------------------------------------------------------------------
307 template<typename TFunc, typename... VarArgs>
309 //--------------------------------------------------------------------------------------
310 {
311  if (!_thread && !_thread->joinable())
312  return;
313  _thread->join();
314 }
315 
316 //--------------------------------------------------------------------------------------
317 template<typename TFunc, typename... VarArgs>
319 //--------------------------------------------------------------------------------------
320 {
321  if (!_thread && !_thread->joinable())
322  return;
323  _thread->detach();
324 }
325 
326 //--------------------------------------------------------------------------------------
327 template<typename TFunc, typename... VarArgs>
329 //--------------------------------------------------------------------------------------
330 {
331  _flag.store(true);
332 }
333 
334 //--------------------------------------------------------------------------------------
335 template<typename TFunc, typename... VarArgs>
337 //--------------------------------------------------------------------------------------
338 {
339  return _flag.load();
340 }
341 
342 //--------------------------------------------------------------------------------------
343 template<typename TFunc, typename... VarArgs> template<std::size_t... Idx>
344 Ptr<std::thread> CFEXPCppThread<TFunc, VarArgs...>::create_thread(const std::tuple<VarArgs...> & tuple, std::index_sequence<Idx...>)
345 //--------------------------------------------------------------------------------------
346 {
347  // 1. version without runner
348  // return CFEXPDataManager<std::thread>::SafeAllocInstance(std::bind(_thread_func, std::get<Idx>(tuple)...));
349  // 2. version with runner allow interrupt the thread
350  auto lambda_runner = [this] { runner(_thread_func, _thread_args, std::index_sequence_for<VarArgs...>()); };
351  return CFEXPDataManager<std::thread>::SafeAllocInstance(std::bind(lambda_runner));
352 }
353 
354 //--------------------------------------------------------------------------------------
355 template<typename TFunc, typename... VarArgs> template<std::size_t... Idx>
356 void CFEXPCppThread<TFunc, VarArgs...>::runner(std::function<TFunc> func, const std::tuple<VarArgs...> & tuple, std::index_sequence<Idx...>)
357 //--------------------------------------------------------------------------------------
358 {
359  _flag_ptr = &_flag;
360  _thread_func(std::get<Idx>(tuple)...);
361 }
362 
368 
371 {
372 public:
373  static Ptr<std::vector<size_t>> GetCpuThreadIds (size_t threads_num);
374  static size_t GetCpuThreadIdToItem(size_t number, size_t threads_num, size_t item_count);
375  static size_t GetNumOfCpuThreads ();
376 protected:
377  // [no protected members] -----------------------------
378 private:
379  // [no private members ] -----------------------------
380 };
381 
382 #endif // !_CFEXPCONCURENCY_H_
std::function< void(void)> t_Procedure
Definition: FEXPConcurency.h:34
virtual char const * what() const override
Definition: FEXPConcurency.h:205
virtual ~CFEXPCppThread()
Definition: FEXPConcurency.h:241
virtual void StartThread()=0
virtual ~ICFEXPConcurrencyBase()
Definition: FEXPConcurency.h:53
CFEXPThreadWin8PLBarrier(std::size_t thread_count)
Definition: FEXPConcurency.cpp:115
const size_t _initial_thrd_count
Definition: FEXPConcurency.h:86
void ThrowIfCancelRequest() noexcept(false)
It throws an exception if cancel of process within the respective thread is required.
Definition: FEXPConcurency.h:215
Base interface for synchronization barrier.
Definition: FEXPConcurency.h:70
virtual void Detach() override
Definition: FEXPConcurency.h:318
virtual void Detach()=0
virtual void Join()=0
Definition: FEXPCommon.h:276
static Ptr< std::vector< size_t > > GetCpuThreadIds(size_t threads_num)
Definition: FEXPConcurency.cpp:161
virtual size_t GetNumberOfThreads()
Definition: FEXPConcurency.h:84
virtual ~ICFEXPThreadBase()
Definition: FEXPConcurency.h:174
It represents CPU thread barrier specific to Windows OS ver. 8 and later.
Definition: FEXPConcurency.h:142
Base interface for concurrency.
Definition: FEXPConcurency.h:50
virtual bool Canceling() override
Definition: FEXPConcurency.h:336
static size_t GetCpuThreadIdToItem(size_t number, size_t threads_num, size_t item_count)
Definition: FEXPConcurency.cpp:175
virtual void Dispose() override
Definition: FEXPConcurency.h:249
void SetInputData(std::function< TFunc > func, std::tuple< VarArgs... > args)
Definition: FEXPConcurency.h:188
virtual bool Canceling()=0
It represents CPU thread autoreseting barrier. It resets its state after the all entering threads are...
Definition: FEXPConcurency.h:113
virtual void Dispose()=0
virtual ~CFEXPThreadWin8PLBarrier()
Definition: FEXPConcurency.h:147
Base interface for handling with threads.
Definition: FEXPConcurency.h:170
virtual void Dispose() override
Definition: FEXPConcurency.cpp:143
virtual ~CFEXPThreadGeneralBarrier()
Definition: FEXPConcurency.h:118
virtual void SynchronizeThreads() override
Definition: FEXPConcurency.cpp:94
std::tuple< VarArgs... > GetInputDataTuple(VarArgs &&... args)
Definition: FEXPConcurency.h:185
Definition: FEXPConcurency.h:31
virtual void StartThread() override
It starts the thread.
Definition: FEXPConcurency.h:298
static Ptr< TType > SafeAllocInstance(VarArgs &&... inpar)
It allocates data.
Definition: FEXPCommon.h:392
virtual void Join() override
Definition: FEXPConcurency.h:308
static size_t GetNumOfCpuThreads()
Definition: FEXPConcurency.cpp:184
virtual ~ICFEXPSynchrThreadBarrier()
Definition: FEXPConcurency.h:75
virtual void Cancel()=0
virtual void Cancel() override
Definition: FEXPConcurency.h:328
virtual void SynchronizeThreads()=0
void SetInputData(std::function< TFunc > func, std::tuple< VarArgs... > args)
Definition: FEXPConcurency.h:287
CFEXPThreadGeneralBarrier(std::size_t thread_count)
Definition: FEXPConcurency.cpp:88
General tools required for paralelism.
Definition: FEXPConcurency.h:370
static bool RunProcedureTask(t_Procedure procedure, bool progressbar)
It runs the asynchronous task.
Definition: FEXPConcurency.cpp:12
static std::enable_if< std::is_base_of< ICFEXPSynchrThreadBarrier, TBarrier >::value, Ptr< TBarrier > >::type GetInstance(std::size_t thread_count)
Definition: FEXPConcurency.h:96
friend void ThrowIfCancelRequest()
It throws an exception if cancel of process within the respective thread is required.
Definition: FEXPConcurency.h:215
virtual void Dispose() override
Definition: FEXPConcurency.h:123
ICFEXPSynchrThreadBarrier(size_t thrd_count)
Definition: FEXPConcurency.h:74
Wrapper above C++ std::thread class.
Definition: FEXPConcurency.h:235
Definition: FEXPConcurency.h:201
virtual void SynchronizeThreads() override
Definition: FEXPConcurency.cpp:129
CFEXPCppThread()
Definition: FEXPConcurency.h:239